; Copyright (c) 2009 Michael Streif
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.


BITS 32

global loader           ; making entry point visible to linker


; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002           ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

section .text
align 4
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM

; reserve initial kernel stack space
STACKSIZE equ 4096                  ; that's 1kb
VIDMEM equ 0xb8000
KERNEL_PHYS equ 0x00180000	     ;at 1,5 MB --> max kernel size: 0,5 MB!

loader:

   mov esp, stack+STACKSIZE           ; set up the stack

   push ebx ;mboot structure

   call setupPaging

   ; enable PAE, support for long mode paging
   mov eax, cr4
   bts eax, 5
   mov cr4, eax

   ; load cr3 with pml4
   mov eax, PML4
   mov cr3, eax

   mov ecx, 0c0000080h			; EFER MSR number.
   rdmsr				; Read EFER.
   bts eax, 8				; Set LME=1.
   wrmsr				; Write EFER.

   ; Enable paging to activate long mode (set CR0.PG=1)
   mov eax, cr0				; Read CR0.
   bts eax, 31				; Set PE=1.
   mov cr0, eax				; Write CR0.

   mov ax, 0x10
   mov ss, ax
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   pop edi  ;multiboot info

   lgdt [pointer]

   jmp 0x08:kernel

setupPaging:
   mov eax, PT
   or eax, 0x03
   mov dword [PD], eax

   mov eax, PD
   or eax, 0x03
   mov dword [PDP], eax

   mov eax, PDP
   or eax, 0x03
   mov dword [PML4], eax


   mov eax, PThigh
   or eax, 0x03
   mov dword [PDhigh], eax

   mov eax, PDhigh
   or eax, 0x03
   mov dword [PDPhigh], eax

   mov eax, PDPhigh
   or eax, 0x03
   mov dword [PML4 + 256 * 8], eax

   ; recursive mapping
   mov eax, PML4
   or eax, 0x03
   mov dword [PML4 + 511 * 8], eax

   ret


section .data

;paging structures
PT:
   %assign i 0
   %rep    512			;2 MB identity
        dd i | 0x03
        dd 0
   %assign i i+4096
   %endrep

PD:
   times 512 dq 0

PDP:
   times 512 dq 0

PThigh:
   %assign i 0
   %rep 512				;from 0 MB phys to 2 MB phys in the higher half
        dd i | 0x03
        dd 0
   %assign i i+4096
   %endrep

PDhigh:
   times 512 dq 0

PDPhigh:
   times 512 dq 0

PML4:
   times 512 dq 0

gdt:
   dd 0
   dd 0

   ;code
   dd 0x00000000
   dd 0x00209A00

   ;data
   dd 0x00000000
   dd 0x00209200

   pointer:
   dw $-gdt-1
   dd gdt

section .bss
stack:
   resb STACKSIZE                     ; reserve 4kb stack on a quadword boundary

section .kernel
kernel:
incbin "kernel.bin"
